use std::cell::RefCell;

#[cfg(test)]
mod tests {
    #[test]
    fn test_unsafe_seq() {
        super::start();
    }
}

/// 从 Rust提供的线程管理工具来看，并没有发现什么特殊的地方，和传统语言的线程管理方式非常相似。
/// 那么， Rust 是如何做到之前宣称的那样默认线程安全的呢?这要归功于 std::marker::Send和
/// std::marker::Sync两个特殊的内置 trait。Send和 Sync被定义于 std::marker 模块中，
/// 它们属于标记 trait，其作用如下:
/// ·实现了 Send 的类型，可以安全地在钱程间传递所有权。也就是说 ，可以跨线程移动。
/// ·实现了 Sync 的类型，可以安全地在结程间传递不可变借用。也就是说，可以跨线程共享。
pub fn start() {
    // 这两个标记 trait反映了 Rust看待线程安全的哲学:
    // 多钱程共享内存并非线程不安全问题所在，问题在于错误地共享数据。
    // 通过 Send 和 Sync 将类型贴上“标签”，由编译器来识别这些类型是否可以在多个线程之间移动或共享，
    // 从而做到在编译期就能发现线程不安全的问题。和 Send/Sync相反的标记是!Send/!Sync，
    // 表示不能在线程间安全传递的类型。
    use std::thread;

    // thread::spawn方法的代码
    // pub fn spawn<F, T>(f: F) -> JoinHandle<T>
    // where
    //     F: FnOnce() -> T,
    //     F: Send + 'static,
    //     T: Send + 'static,
    // {
    //     Builder::new().spawn(f).expect("failed to spawn thread")
    // }
    // spawn 函数中的闭包 F 与闭包的返回类型 T 都被加上了 Send 和 ’static 限定。
    // 其中 Send 限定了闭包的类型以及闭包的返回值都必须是实现了Send 的类型，
    // 只有实现了 Send 的类型才可以在线程间传递。而闭包的类型是和捕获变量相关的，
    // 如果捕获变量的类型实现了 Send，那么闭包就实现了 Send

    // 而’static 限定表示类型 T 只能是非引用类型 (除&’static 之外)。其实这个很容易理解，
    // 闭包在线程间传递，如果直接携带了引用类型，生命周期将无法保证，很容易出现悬垂指针，
    // 造成内存不安全。这是 Rust 绝对不允许出现的情况

    // 既然不允许在线程问直接传递引用， 那么如何才能在多个线程之间安全地共享变量呢? 如果是不可变的变量，
    // 则可以通过 Arc<T>来共享。 Arc<T>是 Rc<T>的线程安全版本，
    // 因为 在 Rc<T>内部并未使用原子操作，所以在多个线程之间共享会出现安全问题:而在 Arc<T>
    // 内部使用了原子操作，所以默认线程安全。
    // Arc<T>实现 Send 和 Sync

    // 只 要 T 是实现了 Send 和 Sync 的类型 ， 那么 Arc<T>也会实现 Send 和 Sync。
    // 值得注意的是， Send 和 Sync 这两个 trait 是 unsafe 的，
    // 这意味 着如果开发者 为自定义类型手 动实现这两个 trait，编译器是不保证线程安全的。
    // 实际上，在 Rust标准库 std::marker模块内部，就为所有类型默认实现了 Send 和 Sync，
    // 换句话说 ，就是为所有类型设定好了默认的线程安全规则

    // #[stable(feature = "rust1", since = "1.0.0")]
    // unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> {}

    // #[stable(feature = "rust1", since = "1.0.0")]
    // unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}

    // &’a T和&’a mut T实现了Send，但是对T的限定不同。 &’a T 要求T必须是实现了 Sync 的类型，
    // 表示只要实现了Sync的类型，其不可变借用就可以安全地在线程间共享; 而&’a mut T
    // 要求 T 必须是实现了 Send 的类型 ，表示只要实现了 Send 的 类型，
    // 其可变借用就可以安全地在钱程间移动。
    // 除在 std::marker模块中标记的上述未实现 Send 和 Sync 的类型之外，在其他模块中也有。
    // 比如 Cell 和 RefCell 都实现了 !Sync，表示它们无法跨线程共享 :
    // 再比如 Rc 实现了!Send， 表示它无法跨线程移动。

    fn test_send<F: Send>(_: F) {}

    fn test_sync<F: Sync>(_: F) {}

    fn test_send_sync<F: Send + Sync>(_: F) {}

    let cell = RefCell::new(1);

    // 使用cell引用编译错误
    // impl<T: ?Sized> !Sync for RefCell<T> {}
    // &’a T 要求T必须是实现了 Sync 的类型，表示只要实现了Sync的类型，
    // 其不可变借用就可以安全地在线程间共享
    // test_send(&cell);

    // unsafe impl<T: ?Sized> Send for RefCell<T> where T: Send {}
    test_send(cell);

    let t = T { a: &mut 1 };
    // i32 是 send + sync的
    // &mut i32 是 send + sync的
    test_send(RefCell::new(&t));

    // i32 是 send + sync的
    // &mut i32 是 send + sync的
    test_sync(&t);

    test_send_sync(&t);
}

struct T<'a, T: 'a> {
    a: &'a mut T,
}
